package configs

import (
	"leeframe/internal/pkg/env"
	"strings"
	"time"

	"github.com/fsnotify/fsnotify"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
)

var config = new(Config)

type Config struct {
	Server struct {
		HttpPort     int           `toml:"HttpPort"`
		ReadTimeout  time.Duration `toml:"ReadTimeout"`
		WriteTimeout time.Duration `toml:"WriteTimeout"`
		Version      string        `toml:"Version"`
		TmpFilePath  string        `toml:"TmpFilePath"`
	} `toml:"server"`

	Mysql struct {
		Host        string `toml:"Host"`
		User        string `toml:"User"`
		Password    string `toml:"Password"`
		Name        string `toml:"Name"`
		TablePrefix string `toml:"TablePrefix"`
		MaxIdle     int    `toml:"MaxIdle"`
		MaxActive   int    `toml:"MaxActive"`
	} `toml:"mysql"`

	Redis struct {
		Host        string        `toml:"Host"`
		Password    string        `toml:"Password"`
		RedisPrefix string        `toml:"RedisPrefix"`
		MaxIdle     int           `toml:"MaxIdle"`
		MaxActive   int           `toml:"MaxActive"`
		RedisDB     int           `toml:"RedisDB"`
		IdleTimeout time.Duration `toml:"IdleTimeout"`
	} `toml:"redis"`

	Language struct {
		Local string `toml:"Local"`
	} `toml:"language"`

	Log struct {
		Level         int    `toml:"Level"`
		LogFormatJson bool   `toml:"LogFormatJson"`
		TimeKey       string `toml:"TimeKey"`
		LevelKey      string `toml:"LevelKey"`
		NameKey       string `toml:"NameKey"`
		CallerKey     string `toml:"CallerKey"`
		MessageKey    string `toml:"MessageKey"`
		StackTrackKey string `toml:"StackTrackKey"`
		MaxSize       int    `toml:"MaxSize"`
		MaxBackups    int    `toml:"MaxBackups"`
		MaxAge        int    `toml:"MaxAge"`
	} `toml:"log"`
}

func Setup() {
	viper.SetConfigName(env.Active().Value() + "_configs")
	viper.SetConfigType("toml")
	viper.AddConfigPath("./configs")

	// file
	if err := viper.ReadInConfig(); err != nil {
		panic(err)
	}

	// env
	viper.AutomaticEnv()
	viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))

	// flag
	pflag.CommandLine.AddGoFlagSet(env.GetFlagCommandLine())
	pflag.Parse()
	err := viper.BindPFlags(pflag.CommandLine)
	if err != nil {
		panic(err)
	}

	if err := viper.Unmarshal(config); err != nil {
		panic(err)
	}

	// 当前配置动态更新后，应用并没有重新加载配置，所以框架目前并不能热更新配置
	// 但是config结构体的值却被Unmarshal改变了，会导致配置取值不一致
	viper.WatchConfig()
	viper.OnConfigChange(func(e fsnotify.Event) {
		if err := viper.Unmarshal(config); err != nil {
			panic(err)
		}
	})
}

func Get() Config {
	return *config
}
